#include "play_connect_handler.h"
#include "event2/event.h"
#include "event2/bufferevent.h"
#include <iostream>
#include <cstring>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "rtsp_proxy_client.h"
#include <sstream>
#include <QRegExp>
#include <QString>

using namespace std;
using namespace rtsp;

PlayConnectHandler *PlayConnectHandler::NewCreate(event_base *base, int socket, const char* player_host, int player_port)
{
    return new PlayConnectHandler(base, socket, player_host, player_port);
}

PlayConnectHandler::PlayConnectHandler(
        event_base* base,
        int socket,
        const char* player_host,
        int player_port)
    : proxy_client_(NULL)
{
    this->bev_ = bufferevent_socket_new(base, socket, BEV_OPT_CLOSE_ON_FREE);
    bufferevent_setcb(this->bev_, OnRead, OnWrite, OnEvent, this);
    bufferevent_enable(this->bev_, EV_READ | EV_WRITE);

    memset(this->player_host_, 0, 16);
    memcpy(this->player_host_, player_host, strlen(player_host));
    this->player_port_ = player_port;

    data_ = new char[data_size_];
    memset(this->data_, 0, data_size_);
}

int PlayConnectHandler::GetRequestChannelNumber(const char *in)
{
    for(int i = 0; i < strlen(in); i++)
    {
        if(memcmp(in + i, "Channels/", 9) == 0 || memcmp(in + i, "channels/", 9) == 0)
        {
            for(int j = i + 9; j < strlen(in); j++)
            {
                if(memcmp(in + j, " ", 1) == 0)
                {
                    char num[5] = {0};
                    memcpy(num, in + i + 9, j - i - 9);
                    return atoi(num);
                }
            }
        }
        if(memcmp(in + i, "tracks/", 7) == 0)
        {
            for(int j = i + 7; j < strlen(in); j++)
            {
                if(memcmp(in + j, "?", 1) == 0)
                {
                    char num[5] = {0};
                    memcpy(num, in + i + 7, j - i - 7);
                    return atoi(num);
                }
            }
        }
    }
    return 0;
}

void PlayConnectHandler::ReplacePacket(const char *in, char *out, const char *host, int port, int channel_num)
{
    // 利用正则表达式进行替换
    QRegExp host_port_rx("(\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+)");
    QRegExp channel_rx("\\d+");
    QString ctx(in);
    int pos = 0;
    int host_port_pos = 0;
    int host_port_len = 0;
    int channel_pos = 0;
    int channel_len = 0;
    if((pos = host_port_rx.indexIn(ctx, pos)) != -1)
    {
        host_port_pos = pos;
        host_port_len = host_port_rx.matchedLength();
        pos += host_port_len;
    }
    if((pos = channel_rx.indexIn(ctx, pos)) != -1)
    {
        channel_pos = pos;
        channel_len = channel_rx.matchedLength();
    }
    if(host_port_pos == 0 || channel_pos == 0)
    {
        return;
    }

    stringstream ss;
    ss << host << ":" << port;
    int out_pos = 0;
    memcpy(out + out_pos, in, host_port_pos);
    out_pos += host_port_pos;
    memcpy(out + out_pos, ss.str().c_str(), ss.str().size());
    out_pos += ss.str().size();
    memcpy(out + out_pos, in + host_port_pos + host_port_len, channel_pos - (host_port_pos + host_port_len));
    out_pos += (channel_pos - (host_port_pos + host_port_len));
    ss.str("");
    ss << channel_num;
    memcpy(out + out_pos, ss.str().c_str(), ss.str().size());
    out_pos += ss.str().size();
    memcpy(out + out_pos, in + channel_pos + channel_len, strlen(in) - (channel_pos + channel_len));
}

void PlayConnectHandler::OnRead(bufferevent *bev, void *ctx)
{

    PlayConnectHandler* h = (PlayConnectHandler*)ctx;
    char out[h->data_size_] = {0};
    int read_len = bufferevent_read(h->bev_, h->data_, h->data_size_);
    h->data_[read_len] = '\0';
    qInfo("播放器消息: \r\n%s\r\n", h->data_);
    int req_channel_num = h->GetRequestChannelNumber(h->data_);
    if(req_channel_num == 0)
    {
        qCritical("不能获取报文请求的通道号");
        return;
    }
    // 根据通道号查询映射表中的摄像机地址信息
    CameraData *camera_info = Config::Get()->GetCameraInfoByChannel(req_channel_num);
    if(!camera_info)
    {
        qCritical("未找到代理通道号对应的摄像机信息");
        return;
    }
    h->ReplacePacket(h->data_, out, camera_info->host, camera_info->port, camera_info->channel_num);
    memcpy(h->data_, out, h->data_size_);

    // 创建网络连接代理并添加连接回调
    if(!h->proxy_client_)
    {
        h->proxy_client_ = new RTSPProxyClient(bufferevent_get_base(bev) ,
                                               camera_info->host,
                                               camera_info->port,
                                               h->player_host_);
        h->proxy_client_->Connect(OnCameraConnected, h);
        return;
    }
    // 添加RTSP方法的回调
    h->proxy_client_->ExecuteMethod(h->data_, OnCameraMethodEvent, h);
}

void PlayConnectHandler::OnWrite(bufferevent *bev, void *ctx)
{

}

void PlayConnectHandler::OnEvent(bufferevent *bev, short what, void *ctx)
{
    PlayConnectHandler *h = (PlayConnectHandler*)ctx;
    if (what & BEV_EVENT_CONNECTED)
    {
        return;
    }
    if (what & BEV_EVENT_ERROR || what & BEV_EVENT_EOF)
    {
        // 播放端关闭后自动释放
        qInfo("播放器(%s)关闭", h->player_host_);
        delete h;
    }
}

void PlayConnectHandler::OnCameraConnected(ConnectEnum type, void* arg)
{
    PlayConnectHandler *h = (PlayConnectHandler*) arg;
    if(type == CONNECTION)
    {
        h->proxy_client_->ExecuteMethod(h->data_, OnCameraMethodEvent, h);
    }
}

void PlayConnectHandler::OnCameraMethodEvent(RtspMethodEnum type, char *msg, void* arg)
{
    // 所有消息直接转发回播放端
    PlayConnectHandler *h = (PlayConnectHandler*) arg;
    bufferevent_write(h->bev_, msg, strlen(msg));
}

PlayConnectHandler::~PlayConnectHandler()
{
    if(bev_)
    {
        bufferevent_free(bev_);
    }
    if(proxy_client_)
    {
        delete proxy_client_;
    }
}

